/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 */

#include "MainSceneRenderer.h"
#include "log.hpp"
#include <array>
#include "Utils.h"
#include "Device.h"
#include "DescriptorPool.h"
#include <glm/gtc/matrix_transform.hpp>
#include <chrono>
#include <cmath>

namespace OHTestApp {
namespace {
// 控制高频操作的日志输出
static bool s_loggedCmdBeginRenderPass = false;
static bool s_loggedCmdBindPipeline = false;
static bool s_loggedCmdBindVertexBuffers = false;
static bool s_loggedCmdDraw = false;
static bool s_loggedCmdEndRenderPass = false;
static bool s_loggedCmdSetViewport = false;
static bool s_loggedCmdSetScissor = false;
static bool s_loggedCmdBindDescriptorSets = false;
static bool s_loggedUpdateDescriptorSets = false;
} // end of anonymous namespace

// 三角形顶点数据（位置 + UV）
struct SimpleVertex {
    glm::vec2 pos;
    glm::vec2 uv;
};

const std::vector<SimpleVertex> g_triangleVertices = {
    {{0.0f, -0.5f}, {0.5f, 0.0f}},   // 底部顶点，UV中心下方
    {{0.5f, 0.5f}, {1.0f, 1.0f}},    // 右上角
    {{-0.5f, 0.5f}, {0.0f, 1.0f}}    // 左上角
};

// uniform buffer结构
struct TriangleUBO {
    glm::mat4 transform;
    glm::vec3 colorMultiplier;
    float time;
};

void MainSceneRenderer::Init(const MainSceneRendererDescriptor &desc)
{
    GOLOGI("Initializing simple triangle renderer");
    m_descriptor = desc;

    CreateVertexBuffer();
    CreateUniformBuffers();
    CreateOpaqueRenderPass();
    CreateOpaqueDescriptorSetLayout();
    CreateOpaqueDescriptorSets();
    CreateOpaqueGraphicsPipeline();
}

void MainSceneRenderer::CreateVertexBuffer()
{
    VkDeviceSize bufferSize = sizeof(g_triangleVertices[0]) * g_triangleVertices.size();
    
    OHTestApp::Buffer::BufferDescriptor bufferDesc;
    bufferDesc.name = "TriangleVertexBuffer";
    bufferDesc.bufferSize = bufferSize;
    bufferDesc.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
    // bufferDesc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    bufferDesc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    m_vertexBuffer.Init(bufferDesc);
    m_vertexBuffer.UpdateData(const_cast<void*>(static_cast<const void*>(g_triangleVertices.data())), bufferSize);
    m_vertexNum = static_cast<uint32_t>(g_triangleVertices.size());
    
    GOLOGI("Created triangle vertex buffer with %d vertices", m_vertexNum);
}

void MainSceneRenderer::CreateUniformBuffers()
{
    OHTestApp::Buffer::BufferDescriptor bufferDesc;
    bufferDesc.name = "TriangleUniformBuffer";
    bufferDesc.bufferSize = sizeof(TriangleUBO);
    bufferDesc.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
    // bufferDesc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    bufferDesc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    m_sceneBuffers.resize(m_descriptor.frameInFlightNum);
    for (auto &buffer : m_sceneBuffers) {
        buffer.Init(bufferDesc);
    }
    
    GOLOGI("Created uniform buffers for triangle rendering");
}

void MainSceneRenderer::CreateDynamicUniformBuffers()
{
    // 此时不需要动态uniform buffer
}

void SetAttachmentDescs(VkAttachmentDescription attachmentDescs[],
    MainSceneRenderer::MainSceneRendererDescriptor &descriptor)
{
    attachmentDescs[0] = (VkAttachmentDescription) {
        .flags = 0U,
        .format = descriptor.colorFormat,
        .samples = VK_SAMPLE_COUNT_1_BIT,
        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
        .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
    };
    attachmentDescs[1] = (VkAttachmentDescription) {
        .flags = 0U,
        .format = descriptor.depthStencilFormat,
        .samples = VK_SAMPLE_COUNT_1_BIT,
        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
        .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
    };
}

void SetDependenciesExt(VkSubpassDependency dependenciesExt[])
{
    dependenciesExt[0] = (VkSubpassDependency) {
        .srcSubpass = VK_SUBPASS_EXTERNAL,
        .dstSubpass = 0U,

        .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
        VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,

        .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,

        .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
        VK_ACCESS_SHADER_READ_BIT,

        .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,

        .dependencyFlags = 0U
    };
    dependenciesExt[1] = (VkSubpassDependency) {
        .srcSubpass = 0U,
        .dstSubpass = VK_SUBPASS_EXTERNAL,

        .srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,

        .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,

        .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,

        .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
        .dependencyFlags = 0U
    };
}

void MainSceneRenderer::CreateOpaqueRenderPass()
{
    VkAttachmentDescription attachmentDescs[2]{};
    SetAttachmentDescs(attachmentDescs, m_descriptor);

    constexpr static VkAttachmentReference colorReference {
        .attachment = 0U,
        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
    };

    constexpr static VkAttachmentReference depthReference {
        .attachment = 1U,
        .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
    };

    constexpr VkSubpassDescription subpassExt {
        .flags = 0U,
        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
        .inputAttachmentCount = 0U,
        .pInputAttachments = nullptr,
        .colorAttachmentCount = 1U,
        .pColorAttachments = &colorReference,
        .pResolveAttachments = nullptr,
        .pDepthStencilAttachment = &depthReference,
        .preserveAttachmentCount = 0U,
        .pPreserveAttachments = nullptr
    };

    static VkSubpassDependency dependenciesExt[2]{};
    SetDependenciesExt(dependenciesExt);

    VkRenderPassCreateInfo const renderPassInfoExt {
        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
        .pNext = nullptr,
        .flags = 0U,
        .attachmentCount = static_cast<uint32_t>(std::size(attachmentDescs)),
        .pAttachments = attachmentDescs,
        .subpassCount = 1U,
        .pSubpasses = &subpassExt,
        .dependencyCount = static_cast<uint32_t>(std::size(dependenciesExt)),
        .pDependencies = dependenciesExt
    };

    VkDevice device = OHTestApp::Device::Instance().GetNativeDevice();
    VkResult result = vkCreateRenderPass(device, &renderPassInfoExt, nullptr, &m_opaqueRenderPass);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateRenderPass completed successfully for Triangle");
        OHTestApp::SetLabel(device, m_opaqueRenderPass, VK_OBJECT_TYPE_RENDER_PASS, "Triangle");
    } else {
        GOLOGE("vkCreateRenderPass failed with error: %d for Triangle", result);
    }
}

void MainSceneRenderer::CreateOpaqueDescriptorSetLayout()
{
    // 仅保留 binding 0: UBO（VS/FS 可共同访问）
    VkDescriptorSetLayoutBinding uboLayoutBinding{};
    uboLayoutBinding.binding = 0;
    uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    uboLayoutBinding.descriptorCount = 1;
    uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
    uboLayoutBinding.pImmutableSamplers = nullptr;

    std::array<VkDescriptorSetLayoutBinding, 1> bindings { uboLayoutBinding };

    VkDescriptorSetLayoutCreateInfo layoutInfo{};
    layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
    layoutInfo.pBindings = bindings.data();

    VkResult result = vkCreateDescriptorSetLayout(OHTestApp::Device::Instance().GetNativeDevice(), &layoutInfo, nullptr,
        &m_opaqueDescriptorSetLayout);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateDescriptorSetLayout completed successfully for Triangle (UBO only)");
    } else {
        GOLOGE("vkCreateDescriptorSetLayout failed with error: %d for Triangle", result);
    }
}

std::unique_ptr<VkPipelineShaderStageCreateInfo[]> MainSceneRenderer::CreateShaderStages(
    VkShaderModule vertShaderModule, VkShaderModule fragShaderModule)
{
    std::unique_ptr<VkPipelineShaderStageCreateInfo[]> shaderStages =
        std::make_unique<VkPipelineShaderStageCreateInfo[]>(2);

    shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
    shaderStages[0].module = vertShaderModule;
    shaderStages[0].pName = "main";

    shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
    shaderStages[1].module = fragShaderModule;
    shaderStages[1].pName = "main";
    
    return shaderStages;
}

void MainSceneRenderer::CreatePipelineLayout(VkDevice device)
{
    VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
    pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    pipelineLayoutInfo.setLayoutCount = 1;
    pipelineLayoutInfo.pSetLayouts = &m_opaqueDescriptorSetLayout;
    pipelineLayoutInfo.pushConstantRangeCount = 0;
    pipelineLayoutInfo.pPushConstantRanges = nullptr;

    VkResult result = vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &m_opaquePipelineLayout);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreatePipelineLayout completed successfully for Triangle");
    } else {
        GOLOGE("vkCreatePipelineLayout failed with error: %d for Triangle", result);
    }
}

VkPipelineDepthStencilStateCreateInfo MainSceneRenderer::CreateDepthStencil()
{
    static VkPipelineDepthStencilStateCreateInfo depthStencil{};
    depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
    depthStencil.depthTestEnable = VK_FALSE; //关闭深度测试
    depthStencil.depthWriteEnable = VK_FALSE;
    depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
    depthStencil.depthBoundsTestEnable = VK_FALSE;
    depthStencil.minDepthBounds = 0.0f; // Optional
    depthStencil.maxDepthBounds = 1.0f; // Optional
    depthStencil.stencilTestEnable = VK_FALSE;
    
    return depthStencil;
}

VkPipelineColorBlendStateCreateInfo MainSceneRenderer::CreateColorBlending()
{
    static VkPipelineColorBlendAttachmentState colorBlendAttachment{};
    colorBlendAttachment.colorWriteMask =
        VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    colorBlendAttachment.blendEnable = VK_FALSE;
    colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;  // Optional
    colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
    colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;             // Optional
    colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;  // Optional
    colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
    colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;             // Optional

    VkPipelineColorBlendStateCreateInfo colorBlending{};
    colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlending.logicOpEnable = VK_FALSE;
    colorBlending.logicOp = VK_LOGIC_OP_COPY; // Optional
    colorBlending.attachmentCount = 1;
    colorBlending.pAttachments = &colorBlendAttachment;
    colorBlending.blendConstants[0] = 0.0f;            // Optional
    colorBlending.blendConstants[1] = 0.0f;            // Optional
    colorBlending.blendConstants[2] = 0.0f;            // Optional
    colorBlending.blendConstants[3] = 0.0f; // Optional

    return colorBlending;
}

VkPipelineRasterizationStateCreateInfo MainSceneRenderer::CreateRasterizerInfo()
{
    static VkPipelineRasterizationStateCreateInfo rasterizer{};
    rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    rasterizer.depthClampEnable = VK_FALSE;
    rasterizer.rasterizerDiscardEnable = VK_FALSE;
    rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
    rasterizer.lineWidth = 1.0f;
    rasterizer.cullMode = VK_CULL_MODE_NONE; //关闭背面剔除
    rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
    rasterizer.depthBiasEnable = VK_FALSE;

    return rasterizer;
}

void MainSceneRenderer::CreatePipeline(VkDevice device, VkPipelineShaderStageCreateInfo *shaderStages,
    VkPipelineVertexInputStateCreateInfo &vertexInputInfo, VkPipelineInputAssemblyStateCreateInfo &inputAssembly,
    VkPipelineRasterizationStateCreateInfo &rasterizer, VkPipelineMultisampleStateCreateInfo &multisampling,
    VkPipelineDepthStencilStateCreateInfo &depthStencil, VkPipelineColorBlendStateCreateInfo &colorBlending)
{
    std::vector<VkDynamicState> dynamicStates = {
        VK_DYNAMIC_STATE_VIEWPORT,
        VK_DYNAMIC_STATE_SCISSOR,
    };

    VkPipelineDynamicStateCreateInfo dynamicState{};
    dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
    dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
    dynamicState.pDynamicStates = dynamicStates.data();

    VkPipelineViewportStateCreateInfo viewportState{};
    viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    viewportState.viewportCount = 1;
    viewportState.scissorCount = 1;

    VkGraphicsPipelineCreateInfo pipelineInfo{};
    pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    pipelineInfo.stageCount = 2;
    pipelineInfo.pStages = shaderStages;
    pipelineInfo.pVertexInputState = &vertexInputInfo;
    pipelineInfo.pInputAssemblyState = &inputAssembly;
    pipelineInfo.pViewportState = &viewportState;
    pipelineInfo.pRasterizationState = &rasterizer;
    pipelineInfo.pMultisampleState = &multisampling;
    pipelineInfo.pDepthStencilState = &depthStencil;
    pipelineInfo.pColorBlendState = &colorBlending;
    pipelineInfo.pDynamicState = &dynamicState;

    pipelineInfo.layout = m_opaquePipelineLayout;
    pipelineInfo.renderPass = m_opaqueRenderPass;
    pipelineInfo.subpass = 0;

    pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
    pipelineInfo.basePipelineIndex = -1;              // Optional

    VkResult result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1U, &pipelineInfo, nullptr, &m_opaqueGraphicsPipeline);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateGraphicsPipelines completed successfully for Triangle");
        OHTestApp::SetLabel(device, m_opaqueGraphicsPipeline, VK_OBJECT_TYPE_PIPELINE, "m_triangleGraphicsPipeline");
    } else {
        GOLOGE("vkCreateGraphicsPipelines failed with error: %d for Triangle", result);
    }
}

void MainSceneRenderer::CreateOpaqueGraphicsPipeline()
{
    // rawfile 的 .spv（HarmonyOS 打包资源路径）
    static const char* kVertCandidates[] = {
        "rawfile/triangle_vert.spv",
    };
    static const char* kFragCandidates[] = {
        "rawfile/triangle_frag.spv",
    };

    std::optional<OHTestApp::AAssetImporter::ShaderAsset> vs;
    std::optional<OHTestApp::AAssetImporter::ShaderAsset> fs;

    for (auto path : kVertCandidates) {
        vs = OHTestApp::AAssetImporter::Instance().ImportShaderAsset(path);
        if (vs.has_value()) {
            GOLOGI("Triangle VS loaded from: %s", path);
            break;
        }
    }
    if (!vs.has_value()) {
        GOLOGE("Load triangle vertex shader asset failed!");
        GOLOGE("Please place SPIR-V in: entry/src/main/resources/rawfile/ as triangle_vert.spv");
        return;
    }

    for (auto path : kFragCandidates) {
        fs = OHTestApp::AAssetImporter::Instance().ImportShaderAsset(path);
        if (fs.has_value()) {
            GOLOGI("Triangle FS loaded from: %s", path);
            break;
        }
    }
    if (!fs.has_value()) {
        GOLOGE("Load triangle fragment shader asset failed!");
        GOLOGE("Please place SPIR-V in: entry/src/main/resources/rawfile/ as triangle_frag.spv");
        return;
    }

    VkShaderModule vertShaderModule = OHTestApp::CreateShaderModule(vs.value().shaderData);
    VkShaderModule fragShaderModule = OHTestApp::CreateShaderModule(fs.value().shaderData);

    std::unique_ptr<VkPipelineShaderStageCreateInfo[]> shaderStages =
        CreateShaderStages(vertShaderModule, fragShaderModule);

    // 顶点输入：pos(vec2) + uv(vec2)
    static VkVertexInputBindingDescription bindingDescription{};
    bindingDescription.binding = 0;
    bindingDescription.stride = sizeof(SimpleVertex);
    bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

    static std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};
    
    // 位置属性
    attributeDescriptions[0].binding = 0;
    attributeDescriptions[0].location = 0;
    attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
    attributeDescriptions[0].offset = offsetof(SimpleVertex, pos);
    
    // UV属性
    attributeDescriptions[1].binding = 0;
    attributeDescriptions[1].location = 1;
    attributeDescriptions[1].format = VK_FORMAT_R32G32_SFLOAT;
    attributeDescriptions[1].offset = offsetof(SimpleVertex, uv);

    VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
    vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    vertexInputInfo.vertexBindingDescriptionCount = 1;
    vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
    vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
    vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();

    VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
    inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
    inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
    inputAssembly.primitiveRestartEnable = VK_FALSE;

    VkPipelineRasterizationStateCreateInfo rasterizer = CreateRasterizerInfo();
    
    VkPipelineMultisampleStateCreateInfo multisampling{};
    multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
    multisampling.sampleShadingEnable = VK_FALSE;
    multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;

    VkPipelineDepthStencilStateCreateInfo depthStencil = CreateDepthStencil();
    VkPipelineColorBlendStateCreateInfo colorBlending = CreateColorBlending();

    VkDevice device = OHTestApp::Device::Instance().GetNativeDevice();
    CreatePipelineLayout(device);
    CreatePipeline(device, shaderStages.get(), vertexInputInfo, inputAssembly, rasterizer, multisampling, depthStencil,
        colorBlending);

    GOLOGD("Destroying fragment shader module");
    vkDestroyShaderModule(device, fragShaderModule, nullptr);
    GOLOGW("vkDestroyShaderModule (fragment) completed successfully");
    
    GOLOGD("Destroying vertex shader module");
    vkDestroyShaderModule(device, vertShaderModule, nullptr);
    GOLOGW("vkDestroyShaderModule (vertex) completed successfully");
}

void MainSceneRenderer::CreateOpaqueDescriptorSets()
{
    std::vector<VkDescriptorSetLayout> layouts(m_descriptor.frameInFlightNum, m_opaqueDescriptorSetLayout);
    VkDescriptorSetAllocateInfo allocInfo{};
    allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    allocInfo.descriptorPool = DescriptorPool::Instance().GetNativeDescriptorPool();
    allocInfo.descriptorSetCount = static_cast<uint32_t>(m_descriptor.frameInFlightNum);
    allocInfo.pSetLayouts = layouts.data();

    m_opaqueDescriptorSets.resize(m_descriptor.frameInFlightNum);
    VkResult result = vkAllocateDescriptorSets(OHTestApp::Device::Instance().GetNativeDevice(), &allocInfo,
        m_opaqueDescriptorSets.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkAllocateDescriptorSets completed successfully for Triangle");
    } else {
        GOLOGE("vkAllocateDescriptorSets failed with error: %d for Triangle", result);
        m_opaqueDescriptorSets.clear();
        return;
    }

    for (size_t i = 0; i < m_descriptor.frameInFlightNum; ++i) {
        VkDescriptorBufferInfo bufferInfo{};
        bufferInfo.buffer = m_sceneBuffers[i].GetNativeBuffer();
        bufferInfo.offset = 0;
        bufferInfo.range = sizeof(TriangleUBO);

        std::array<VkWriteDescriptorSet, 1> writes{};

        // 写入UBO @ binding 0
        writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        writes[0].dstSet = m_opaqueDescriptorSets[i];
        writes[0].dstBinding = 0;
        writes[0].dstArrayElement = 0;
        writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        writes[0].descriptorCount = 1;
        writes[0].pBufferInfo = &bufferInfo;

        vkUpdateDescriptorSets(OHTestApp::Device::Instance().GetNativeDevice(), static_cast<uint32_t>(writes.size()),
            writes.data(), 0, nullptr);

        if (!s_loggedUpdateDescriptorSets) {
            GOLOGW("vkUpdateDescriptorSets completed successfully");
            s_loggedUpdateDescriptorSets = true;
        }
    }
    
    GOLOGW("Triangle descriptor sets updated successfully (UBO only)");
}

void MainSceneRenderer::Update(uint32_t frameIdx)
{
    static std::chrono::time_point<std::chrono::steady_clock> s_start = std::chrono::steady_clock::now();
    std::chrono::time_point<std::chrono::steady_clock> s_now = std::chrono::steady_clock::now();
    auto deltaT = std::chrono::duration_cast<std::chrono::microseconds>(s_now - s_start).count();
    float time = deltaT / 1000000.0f;

    TriangleUBO ubo{};
    
    // 静止三角形
    ubo.transform = glm::mat4(1.0f);
    
    // 颜色随时间变化（正弦波），实现“会变色”
    ubo.colorMultiplier = glm::vec3(
        0.5f + 0.5f * sin(time),
        0.5f + 0.5f * sin(time + 2.0f),
        0.5f + 0.5f * sin(time + 4.0f)
    );
    
    ubo.time = time;

    m_sceneBuffers[frameIdx].UpdateData(&ubo, sizeof(TriangleUBO));
}

VkRenderPassBeginInfo GetRenderPassInfo(VkRenderPass &opaqueRenderPass, VkFramebuffer framebuffer,
    MainSceneRenderer::MainSceneRendererDescriptor &descriptor, VkClearValue clearValues[], uint32_t clearValueCount)
{
    VkRenderPassBeginInfo const renderPassInfo {
        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
        .pNext = nullptr,
        .renderPass = opaqueRenderPass,
        .framebuffer = framebuffer,

        .renderArea {
            .offset {
                .x = 0,
                .y = 0
            },

            .extent = {
                .width = descriptor.frameBufferWidth,
                .height = descriptor.frameBufferHeight
            }
        },

        .clearValueCount = clearValueCount,
        .pClearValues = clearValues
    };

    return renderPassInfo;
}

void MainSceneRenderer::Render(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer, size_t fifIndex)
{
    // 避免向驱动提交无效对象导致崩溃
    if (framebuffer == VK_NULL_HANDLE) {
        GOLOGE("Render skipped: framebuffer is VK_NULL_HANDLE");
        return;
    }
    if (m_opaqueRenderPass == VK_NULL_HANDLE) {
        GOLOGE("Render skipped: m_opaqueRenderPass is VK_NULL_HANDLE");
        return;
    }
    if (m_opaqueGraphicsPipeline == VK_NULL_HANDLE || m_opaquePipelineLayout == VK_NULL_HANDLE) {
        GOLOGE("Render skipped: pipeline or pipeline layout not ready");
        return;
    }
    if (m_vertexNum == 0 || m_vertexBuffer.GetNativeBuffer() == VK_NULL_HANDLE) {
        GOLOGE("Render skipped: vertex buffer not ready");
        return;
    }
    if (fifIndex >= m_opaqueDescriptorSets.size()) {
        GOLOGE("Render skipped: fifIndex(%zu) out of range(%zu)", fifIndex, m_opaqueDescriptorSets.size());
        return;
    }
    if (m_opaqueDescriptorSets.empty() || m_opaqueDescriptorSets[fifIndex] == VK_NULL_HANDLE) {
        GOLOGE("Render skipped: descriptor set not ready");
        return;
    }

    OHTestApp::DebugGroup const group(commandBuffer, "Triangle Render");

    VkClearValue clearValues[] = {
        {
            .color {
                .float32{0.0F, 0.0F, 0.0F, 1.0F}
            }
        },
        {
            .depthStencil {
                .depth = 1.0F,
                .stencil = 0
            }
        }
    };

    VkRenderPassBeginInfo renderPassInfo = GetRenderPassInfo(m_opaqueRenderPass, framebuffer, m_descriptor, clearValues,
        static_cast<uint32_t>(std::size(clearValues)));
    
    VkExtent2D const &extent = renderPassInfo.renderArea.extent;

    vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
    if (!s_loggedCmdBeginRenderPass) {
        GOLOGW("vkCmdBeginRenderPass completed successfully");
        s_loggedCmdBeginRenderPass = true;
    }

    vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_opaqueGraphicsPipeline);
    if (!s_loggedCmdBindPipeline) {
        GOLOGW("vkCmdBindPipeline completed successfully");
        s_loggedCmdBindPipeline = true;
    }

    VkBuffer vertexBuffer = m_vertexBuffer.GetNativeBuffer();
    constexpr VkDeviceSize offsets = 0U;
    vkCmdBindVertexBuffers(commandBuffer, 0U, 1U, &vertexBuffer, &offsets);
    if (!s_loggedCmdBindVertexBuffers) {
        GOLOGW("vkCmdBindVertexBuffers completed successfully");
        s_loggedCmdBindVertexBuffers = true;
    }

    VkViewport const viewport {
        .x = 0.0F,
        .y = 0.0F,
        .width = static_cast<float>(extent.width),
        .height = static_cast<float>(extent.height),
        .minDepth = 0.0F,
        .maxDepth = 1.0F
    };

    VkRect2D const scissor {
        .offset {
            .x = 0,
            .y = 0
        },
        .extent = extent
    };

    vkCmdSetViewport(commandBuffer, 0U, 1U, &viewport);
    if (!s_loggedCmdSetViewport) {
        GOLOGW("vkCmdSetViewport completed successfully");
        s_loggedCmdSetViewport = true;
    }
    vkCmdSetScissor(commandBuffer, 0U, 1U, &scissor);
    if (!s_loggedCmdSetScissor) {
        GOLOGW("vkCmdSetScissor completed successfully");
        s_loggedCmdSetScissor = true;
    }

    vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_opaquePipelineLayout, 0U, 1U,
        &m_opaqueDescriptorSets[fifIndex], 0, nullptr);
    if (!s_loggedCmdBindDescriptorSets) {
        GOLOGW("vkCmdBindDescriptorSets completed successfully");
        s_loggedCmdBindDescriptorSets = true;
    }

    vkCmdDraw(commandBuffer, m_vertexNum, 1U, 0U, 0U);
    if (!s_loggedCmdDraw) {
        GOLOGW("vkCmdDraw completed successfully for triangle");
        s_loggedCmdDraw = true;
    }

    vkCmdEndRenderPass(commandBuffer);
    if (!s_loggedCmdEndRenderPass) {
        GOLOGW("vkCmdEndRenderPass completed successfully");
        s_loggedCmdEndRenderPass = true;
    }
}

VkRenderPass MainSceneRenderer::GetRenderPass() const
{
    return m_opaqueRenderPass;
}

void MainSceneRenderer::Destroy()
{
    VkDevice device = OHTestApp::Device::Instance().GetNativeDevice();

    // 释放并清空 descriptor sets（仅当非空）
    if (!m_opaqueDescriptorSets.empty()) {
        VkResult freeRes = vkFreeDescriptorSets(device, DescriptorPool::Instance().GetNativeDescriptorPool(),
            static_cast<uint32_t>(m_opaqueDescriptorSets.size()), m_opaqueDescriptorSets.data());
        if (freeRes == VK_SUCCESS) {
            GOLOGW("vkFreeDescriptorSets completed successfully");
        } else {
            GOLOGE("vkFreeDescriptorSets failed with error: %d", freeRes);
        }
        m_opaqueDescriptorSets.clear();
    }

    // 销毁图形管线与布局
    if (m_opaqueGraphicsPipeline != VK_NULL_HANDLE) {
        vkDestroyPipeline(device, m_opaqueGraphicsPipeline, nullptr);
        GOLOGW("vkDestroyPipeline completed successfully");
        m_opaqueGraphicsPipeline = VK_NULL_HANDLE;
    }
    if (m_opaquePipelineLayout != VK_NULL_HANDLE) {
        vkDestroyPipelineLayout(device, m_opaquePipelineLayout, nullptr);
        GOLOGW("vkDestroyPipelineLayout completed successfully");
        m_opaquePipelineLayout = VK_NULL_HANDLE;
    }

    // 销毁 descriptor set layout
    if (m_opaqueDescriptorSetLayout != VK_NULL_HANDLE) {
        vkDestroyDescriptorSetLayout(device, m_opaqueDescriptorSetLayout, nullptr);
        GOLOGW("vkDestroyDescriptorSetLayout completed successfully");
        m_opaqueDescriptorSetLayout = VK_NULL_HANDLE;
    }

    // 销毁 render pass
    if (m_opaqueRenderPass != VK_NULL_HANDLE) {
        vkDestroyRenderPass(device, m_opaqueRenderPass, nullptr);
        GOLOGW("vkDestroyRenderPass completed successfully");
        m_opaqueRenderPass = VK_NULL_HANDLE;
    }

    // 销毁 UBO 与顶点缓冲
    for (auto &buffer : m_sceneBuffers) {
        buffer.Destroy();
    }
    m_sceneBuffers.clear();

    m_vertexBuffer.Destroy();
    m_vertexNum = 0;

    m_descriptor = MainSceneRendererDescriptor();
}

} // namespace OHTestApp